using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Security.Principal;
using System.Web;
using System.Web.Caching;
using System.Xml;
using System.Xml.Serialization;
using newtelligence.DasBlog.Runtime;
using newtelligence.DasBlog.Runtime.Proxies;
using newtelligence.DasBlog.Util;
using newtelligence.DasBlog.Web.Core;

namespace newtelligence.DasBlog.Web
{
    /*
    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    // STOP! STOP! STOP! STOP!
    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    // If you want to add entries, please add the properties
    // just above the comment tag at the bottom. SiteConfig
    // is now exposed through a WebService and not putting
    // the properties at the right place will break clients.
    */

    [XmlType(Namespace="urn:newtelligence-com:dasblog:config")]
    [XmlRoot(Namespace="urn:newtelligence-com:dasblog:config")]
    public class SiteConfig
    {
        private string title = "(none)";
        private string subtitle = "(none)";
        private string contact = "(none)";
        private string theme = "default";
        private string root = "(none)";
        private string copyright = "(none)";
        private string description = "";
        private string frontPageCategory = "";
        private int frontPageDayCount = 10;
        private int frontPageEntryCount = 50;
        private bool categoryAllEntries = true;
        private int rssDayCount = 10;
        private int rssMainEntryCount = 50;
        private int rssEntryCount = 50;
        private bool enableRssItemFooters = false;
        private string rssItemFooter;
        private bool alwaysIncludeContentInRSS = false;
        private bool entryTitleAsLink = false;
        private bool notifyWebLogsDotCom = false;
        private bool notifyBloGs = false;
        private bool obfuscateEmail = true;
        private string notificationEmailAddress = null;
        private bool sendCommentsByEmail = false;
        private bool sendPingbacksByEmail = false;
        private bool sendTrackbacksByEmail = false;
        private bool sendReferralsByEmail = false;
        private bool sendPostsByEmail = false;
        private bool enableBloggerApi = true;
        private bool enableComments = true;
        private bool enableCommentApi = true;
        private bool enableConfigEditService = false;
        private bool showCommentCount = true;
        private bool enableAutoPingback = true;
        private bool enableEditService = false;
        private bool enableTrackbackService = true;
        private bool enablePingbackService = true;
        private bool applyContentFiltersToWeb = true;
        private bool applyContentFiltersToRSS = false;
        private bool showItemDescriptionInAggregatedViews = false;
        private bool enableStartPageCaching = false;
        private bool enableBlogrollDescription = false;
        private bool enableUrlRewriting = false;
        private bool enableFtb = true;
        private bool useUserCulture = true;
        private int displayTimeZoneIndex = 90; // this is GMT
        private bool adjustDisplayTimeZone = false;
        private string editPassword;
        private string contentDir;
        private string logDir;
        private string binariesDir;
        private string profilesDir;
        private string smtpServer = null;
        private bool enablePop3 = false;
        private string pop3Server = null;
        private string pop3Username = null;
        private string pop3Password = null;
        private string pop3SubjectPrefix = null;
        private bool pop3InlineAttachedPictures = false;
        private int pop3InlinedAttachedPicturesThumbHeight = 0;
        private int pop3Interval = 240;
        private bool enableXSSUpstream = false;
        private string xssUpstreamEndpoint = "http://radio.xmlstoragesystem.com/RPC2";
        private string xssUpstreamUsername = null;
        private string xssUpstreamPassword = null;
        private string xssRSSFilename = "rss-dasblog.xml";
        private int xssUpstreamInterval = 60*60;
        private bool enableClickThrough = false;
        private bool enableAggregatorBugging = false;
        private bool enableCrossposts = true;
        private bool enableCrossPostFooter = false;
        private string crossPostFooter = null;
        private bool enableTitlePermaLink = false;
        private bool enableTitlePermaLinkUnique = false;
        private bool enableTitlePermaLinkSpaces = false;
        private bool enableEntryReferrals = false;
        private PingServiceCollection pingServices = new PingServiceCollection();
        private int daysCommentsAllowed = 0;
        private bool enableCommentDays = false;
        private string entryEditControl;
        private bool logBlockedReferrals = false;
        private bool showCommentsWhenViewingEntry = false;
        private bool enableAutoSave = false;

        private bool enableCoComment = true;
        private bool commentsRequireApproval;
        private bool commentsAllowHtml;
        private ValidTagCollection allowedTags;
        // default tags
        private const string defaultAllowedTags = "b,i,u,a@href@title,strong,blockquote@cite,em,strike,sup,sub";

        //allow gravatar integration
        private bool commentsAllowGravatar = false;
        private string commentsGravatarNoImgPath = null;
        private string commentsGravatarSize = null;
        private string commentsGravatarBorder = null;
        private string commentsGravatarRating = null;

        // supress email address display
        private bool supressEmailAddressDisplay = false;

        // Allow user to choose default blogging API
        // Can be "Moveable Type", "MetaWeblog" or "Blogger"
        private string preferredBloggingAPI = "Moveable Type";

        private ContentFilterCollection contentFilters = new ContentFilterCollection();
        private CrosspostSiteCollection crosspostSites = new CrosspostSiteCollection();

        public static void Save(SiteConfig siteConfig)
        {
            WindowsImpersonationContext wi = Impersonation.Impersonate();

            XmlSerializer ser = new XmlSerializer(typeof (SiteConfig));

            using (StreamWriter writer = new StreamWriter(GetConfigFilePathFromCurrentContext()))
            {
                ser.Serialize(writer, siteConfig);
            }

            wi.Undo();
        }

        public static SiteConfig GetSiteConfig()
        {
            SiteConfig config = (SiteConfig) HttpContext.Current.Cache["SiteConfig"];

            if (config == null)
            {
                string path = GetConfigFilePathFromCurrentContext();
                config = GetSiteConfig(path);
                HttpContext.Current.Cache.Insert("SiteConfig", config, new CacheDependency(path));
            }

            return config;
        }

        public static SiteConfig GetSiteConfig(string configPath)
        {
            SiteConfig config;
            XmlSerializer ser = new XmlSerializer(typeof (SiteConfig));

            using (StreamReader reader = new StreamReader(configPath))
            {
                config = ser.Deserialize(reader) as SiteConfig;
            }

            return config;
        }

        public static string GetConfigFilePathFromCurrentContext()
        {
            return SiteUtilities.MapPath("~/SiteConfig/site.config");
        }

        public static string GetSecurityFilePathFromCurrentContext()
        {
            return SiteUtilities.MapPath("~/SiteConfig/siteSecurity.config");
        }

        public static string GetConfigPathFromCurrentContext()
        {
            return SiteUtilities.MapPath("~/SiteConfig/");
        }

        public static string GetContentPathFromCurrentContext()
        {
            return SiteUtilities.MapPath(GetSiteConfig().ContentDir);
        }

        public static string GetLogPathFromCurrentContext()
        {
            return SiteUtilities.MapPath(GetSiteConfig().LogDir);
        }

        public static string GetBinariesPathFromCurrentContext()
        {
            return SiteUtilities.MapPath(GetSiteConfig().BinariesDir);
        }

        public static string GetProfilesPathFromCurrentContext()
        {
            return SiteUtilities.MapPath(GetSiteConfig().ProfilesDir);
        }

        private static string CheckTrailingSlashAndRooted(string path)
        {
            if (path == null)
            {
                return path;
            }

            if (path[0] != '~' && path[0] != '/')
            {
                path = "~/" + path;
            }

            if (path[path.Length - 1] != '/')
            {
                return path + '/';
            }
            else
            {
                return path;
            }
        }

        private WindowsTimeZone windowsTimeZone = null;

        public WindowsTimeZone GetConfiguredTimeZone()
        {
            if (windowsTimeZone == null)
            {
                windowsTimeZone = WindowsTimeZone.TimeZones.GetByZoneIndex(displayTimeZoneIndex);
            }

            return windowsTimeZone;
        }

        public string Title
        {
            get { return title; }
            set { title = value; }
        }

        public string Subtitle
        {
            get { return subtitle; }
            set { subtitle = value; }
        }

        public string Theme
        {
            get { return theme; }
            set { theme = value; }
        }

        public string Description
        {
            get { return description; }
            set { description = value; }
        }

        public string Contact
        {
            get { return contact; }
            set { contact = value; }
        }

        public string Root
        {
            get
            {
                if (root[root.Length - 1] != '/')
                {
                    root = root + "/";
                }
                return root;
            }
            set
            {
                root = value;
                if (root[root.Length - 1] != '/')
                {
                    root = root + "/";
                }
            }
        }

        public string Copyright
        {
            get { return copyright; }
            set { copyright = value; }
        }

        public int RssDayCount
        {
            get { return rssDayCount; }
            set { rssDayCount = value; }
        }

        public int RssMainEntryCount
        {
            get { return rssMainEntryCount; }
            set { rssMainEntryCount = value; }
        }

        public int RssEntryCount
        {
            get { return rssEntryCount; }
            set { rssEntryCount = value; }
        }

        public bool EnableRssItemFooters
        {
            get { return enableRssItemFooters; }
            set { enableRssItemFooters = value; }
        }

        public string RssItemFooter
        {
            get { return rssItemFooter; }
            set { rssItemFooter = value; }
        }

        public int FrontPageDayCount
        {
            get { return frontPageDayCount; }
            set { frontPageDayCount = value; }
        }

        public int FrontPageEntryCount
        {
            get { return frontPageEntryCount; }
            set { frontPageEntryCount = value; }
        }

        public bool CategoryAllEntries
        {
            get { return categoryAllEntries; }
            set { categoryAllEntries = value; }
        }

        public string FrontPageCategory
        {
            get { return frontPageCategory; }
            set { frontPageCategory = value; }
        }

        public bool AlwaysIncludeContentInRSS
        {
            get { return alwaysIncludeContentInRSS; }
            set { alwaysIncludeContentInRSS = value; }
        }

        public bool EntryTitleAsLink
        {
            get { return entryTitleAsLink; }
            set { entryTitleAsLink = value; }
        }

        [Obsolete]
        public bool NotifyWebLogsDotCom
        {
            get { return notifyWebLogsDotCom; }
            set { notifyWebLogsDotCom = value; }
        }

        [Obsolete]
        public bool NotifyBloGs
        {
            get { return notifyBloGs; }
            set { notifyBloGs = value; }
        }

        public bool ObfuscateEmail
        {
            get { return obfuscateEmail; }
            set { obfuscateEmail = value; }
        }

        public string NotificationEMailAddress
        {
            get { return notificationEmailAddress; }
            set { notificationEmailAddress = value; }
        }

        public bool SendCommentsByEmail
        {
            get { return sendCommentsByEmail; }
            set { sendCommentsByEmail = value; }
        }

        public bool SendReferralsByEmail
        {
            get { return sendReferralsByEmail; }
            set { sendReferralsByEmail = value; }
        }

        public bool SendTrackbacksByEmail
        {
            get { return sendTrackbacksByEmail; }
            set { sendTrackbacksByEmail = value; }
        }

        public bool SendPingbacksByEmail
        {
            get { return sendPingbacksByEmail; }
            set { sendPingbacksByEmail = value; }
        }

        public bool SendPostsByEmail
        {
            get { return sendPostsByEmail; }
            set { sendPostsByEmail = value; }
        }

        public bool EnableBloggerApi
        {
            get { return enableBloggerApi; }
            set { enableBloggerApi = value; }
        }

        public bool EnableComments
        {
            get { return enableComments; }
            set { enableComments = value; }
        }

        public bool EnableCommentApi
        {
            get { return enableCommentApi; }
            set { enableCommentApi = value; }
        }

        public bool EnableConfigEditService
        {
            get { return enableConfigEditService; }
            set { enableConfigEditService = value; }
        }

        public bool EnableEditService
        {
            get { return enableEditService; }
            set { enableEditService = value; }
        }

        public bool EnableAutoPingback
        {
            get { return enableAutoPingback; }
            set { enableAutoPingback = value; }
        }

        public bool ShowCommentCount
        {
            get { return showCommentCount; }
            set { showCommentCount = value; }
        }

        public bool EnableTrackbackService
        {
            get { return enableTrackbackService; }
            set { enableTrackbackService = value; }
        }

        public bool EnablePingbackService
        {
            get { return enablePingbackService; }
            set { enablePingbackService = value; }
        }

        public bool EnableStartPageCaching
        {
            get { return enableStartPageCaching; }
            set { enableStartPageCaching = value; }
        }

        public bool EnableBlogrollDescription
        {
            get { return enableBlogrollDescription; }
            set { enableBlogrollDescription = value; }
        }

        public bool EnableUrlRewriting
        {
            get { return enableUrlRewriting; }
            set { enableUrlRewriting = value; }
        }

        [Obsolete("FreeTextBox is always enabled")]
        public bool EnableFtb
        {
            get { return enableFtb; }
            set { enableFtb = value; }
        }

        public bool EnableCrossposts
        {
            get { return enableCrossposts; }
            set { enableCrossposts = value; }
        }

        public bool UseUserCulture
        {
            get { return useUserCulture; }
            set { useUserCulture = value; }
        }

        public bool ShowItemDescriptionInAggregatedViews
        {
            get { return showItemDescriptionInAggregatedViews; }
            set { showItemDescriptionInAggregatedViews = value; }
        }

        public bool EnableClickThrough
        {
            get { return enableClickThrough; }
            set { enableClickThrough = value; }
        }

        public bool EnableAggregatorBugging
        {
            get { return enableAggregatorBugging; }
            set { enableAggregatorBugging = value; }
        }


        public int DisplayTimeZoneIndex
        {
            get { return displayTimeZoneIndex; }
            set
            {
                displayTimeZoneIndex = value;
                windowsTimeZone = WindowsTimeZone.TimeZones.GetByZoneIndex(displayTimeZoneIndex);
            }
        }

        public bool AdjustDisplayTimeZone
        {
            get { return adjustDisplayTimeZone; }
            set { adjustDisplayTimeZone = value; }
        }

        public string EditPassword
        {
            get { return editPassword; }
            set { editPassword = value; }
        }

        public string ContentDir
        {
            get { return CheckTrailingSlashAndRooted(contentDir); }
            set { contentDir = value; }
        }

        public string LogDir
        {
            get { return CheckTrailingSlashAndRooted(logDir); }
            set { logDir = value; }
        }

        public string BinariesDir
        {
            get { return CheckTrailingSlashAndRooted(binariesDir); }
            set { binariesDir = value; }
        }

        public string ProfilesDir
        {
            get { return CheckTrailingSlashAndRooted(profilesDir); }
            set { profilesDir = value; }
        }

        public string BinariesDirRelative
        {
            get
            {
                string retVal = BinariesDir;
                retVal = retVal.TrimStart('~');
                retVal = retVal.TrimStart('/');
                return retVal;
            }
        }

        public string SmtpServer
        {
            get { return smtpServer; }
            set { smtpServer = value; }
        }

        public bool EnablePop3
        {
            get { return enablePop3; }
            set { enablePop3 = value; }
        }

        public string Pop3Server
        {
            get { return pop3Server; }
            set { pop3Server = value; }
        }

        public string Pop3Username
        {
            get { return pop3Username; }
            set { pop3Username = value; }
        }

        public string Pop3Password
        {
            get { return pop3Password; }
            set { pop3Password = value; }
        }

        public string Pop3SubjectPrefix
        {
            get { return pop3SubjectPrefix; }
            set { pop3SubjectPrefix = value; }
        }

        public int Pop3Interval
        {
            get { return pop3Interval; }
            set { pop3Interval = value; }
        }

        public bool Pop3InlineAttachedPictures
        {
            get { return pop3InlineAttachedPictures; }
            set { pop3InlineAttachedPictures = value; }
        }

        public int Pop3InlinedAttachedPicturesThumbHeight
        {
            get { return pop3InlinedAttachedPicturesThumbHeight; }
            set { pop3InlinedAttachedPicturesThumbHeight = value; }
        }

        public bool ApplyContentFiltersToWeb
        {
            get { return applyContentFiltersToWeb; }
            set { applyContentFiltersToWeb = value; }
        }

        public bool ApplyContentFiltersToRSS
        {
            get { return applyContentFiltersToRSS; }
            set { applyContentFiltersToRSS = value; }
        }

        public bool EnableXSSUpstream
        {
            get { return enableXSSUpstream; }
            set { enableXSSUpstream = value; }
        }

        public string XSSUpstreamEndpoint
        {
            get { return xssUpstreamEndpoint; }
            set { xssUpstreamEndpoint = value; }
        }

        public string XSSUpstreamUsername
        {
            get { return xssUpstreamUsername; }
            set { xssUpstreamUsername = value; }
        }

        public string XSSUpstreamPassword
        {
            get { return xssUpstreamPassword; }
            set { xssUpstreamPassword = value; }
        }

        public string XSSRSSFilename
        {
            get { return xssRSSFilename; }
            set { xssRSSFilename = value; }
        }

        public int XSSUpstreamInterval
        {
            get { return xssUpstreamInterval; }
            set { xssUpstreamInterval = value; }
        }

        [XmlIgnore]
        public ContentFilterCollection ContentFilters
        {
            get { return contentFilters; }
        }

        [XmlArray("ContentFilters")]
        public ContentFilter[] ContentFilterArray
        {
            get { return new ArrayList(contentFilters).ToArray(typeof (ContentFilter)) as ContentFilter[]; }
            set
            {
                if (value == null)
                {
                    contentFilters = new ContentFilterCollection();
                }
                else
                {
                    contentFilters = new ContentFilterCollection(value);
                }
            }
        }

        [XmlIgnore]
        public CrosspostSiteCollection CrosspostSites
        {
            get { return crosspostSites; }
        }

        [XmlArray("CrosspostSites")]
        public CrosspostSite[] CrosspostSiteArray
        {
            get { return new List<CrosspostSite>(CrosspostSites).ToArray(); }
            set
            {
                if (value == null)
                {
                    crosspostSites = new CrosspostSiteCollection();
                }
                else
                {
                    crosspostSites = new CrosspostSiteCollection(value);
                }
            }
        }

        private bool pop3DeleteAllMessages = false;

        public bool Pop3DeleteAllMessages
        {
            get { return pop3DeleteAllMessages; }
            set { pop3DeleteAllMessages = value; }
        }

        private bool pop3LogIgnoredEmails = true;

        public bool Pop3LogIgnoredEmails
        {
            get { return pop3LogIgnoredEmails; }
            set { pop3LogIgnoredEmails = value; }
        }

        private bool enableReferralUrlBlackList = false;

        public bool EnableReferralUrlBlackList
        {
            get { return enableReferralUrlBlackList; }
            set { enableReferralUrlBlackList = value; }
        }

        private string referralUrlBlackList = String.Empty;

        public string ReferralUrlBlackList
        {
            get { return referralUrlBlackList; }
            set { referralUrlBlackList = value; }
        }

        [XmlIgnore]
        public string[] ReferralUrlBlackListArray
        {
            get { return referralUrlBlackList.Split(new char[] {(';')}); }
        }

        private bool enableCaptcha = true;

        public bool EnableCaptcha
        {
            get { return enableCaptcha; }
            set { enableCaptcha = value; }
        }

        private bool enableReferralUrlBlackList404s = true;

        public bool EnableReferralUrlBlackList404s
        {
            get { return enableReferralUrlBlackList404s; }
            set { enableReferralUrlBlackList404s = value; }
        }

        private bool enableMovableTypeBlackList = false;

        public bool EnableMovableTypeBlackList
        {
            get { return enableMovableTypeBlackList; }
            set { enableMovableTypeBlackList = value; }
        }

        private string channelImageUrl;

        public string ChannelImageUrl
        {
            get { return channelImageUrl; }
            set { channelImageUrl = value; }
        }

        public bool EnableCrossPostFooter
        {
            get { return enableCrossPostFooter; }
            set { enableCrossPostFooter = value; }
        }

        public string CrossPostFooter
        {
            get { return crossPostFooter; }
            set { crossPostFooter = value; }
        }

        public bool EnableTitlePermaLink
        {
            get { return enableTitlePermaLink; }
            set { enableTitlePermaLink = value; }
        }

        public bool EnableTitlePermaLinkUnique
        {
            get { return enableTitlePermaLinkUnique; }
            set { enableTitlePermaLinkUnique = value; }
        }

        public bool EnableTitlePermaLinkSpaces
        {
            get { return enableTitlePermaLinkSpaces; }
            set { enableTitlePermaLinkSpaces = value; }
        }

        private bool encryptLoginPassword = false;

        public bool EncryptLoginPassword
        {
            get { return encryptLoginPassword; }
            set { encryptLoginPassword = value; }
        }

        private bool enableSmtpAuthentication = false;

        public bool EnableSmtpAuthentication
        {
            get { return enableSmtpAuthentication; }
            set { enableSmtpAuthentication = value; }
        }

        private string smtpUserName = null;

        public string SmtpUserName
        {
            get { return smtpUserName; }
            set { smtpUserName = value; }
        }

        private string smtpPassword = null;

        public string SmtpPassword
        {
            get { return smtpPassword; }
            set { smtpPassword = value; }
        }

        private string rssLanguage = null;

        public string RssLanguage
        {
            get { return rssLanguage; }
            set { rssLanguage = value; }
        }

        private bool enableSearchHighlight = true;

        public bool EnableSearchHighlight
        {
            get { return enableSearchHighlight; }
            set { enableSearchHighlight = value; }
        }

        public bool EnableEntryReferrals
        {
            get { return enableEntryReferrals; }
            set { enableEntryReferrals = value; }
        }

        [XmlArray("PingServices")]
        public PingService[] PingServiceArray
        {
            get { return new List<PingService>(PingServices).ToArray(); }
            set
            {
                if (value == null)
                {
                    pingServices = new PingServiceCollection();
                }
                else
                {
                    pingServices = new PingServiceCollection(value);
                }
            }
        }

        [XmlIgnore]
        public PingServiceCollection PingServices
        {
            get
            {
                // if the user has upgraded we want to maintain their settings
                if (pingServices.Count == 0)
                {
                    if (notifyBloGs)
                    {
                        pingServices.Add(PingService.GetBloGs());
                    }

                    if (notifyWebLogsDotCom)
                    {
                        pingServices.Add(PingService.GetWebLogsDotCom());
                    }
                }

                return pingServices;
            }
            set { pingServices = value; }
        }

        private string feedBurnerName = null;

        public string FeedBurnerName
        {
            get { return feedBurnerName; }
            set { feedBurnerName = value; }
        }

        public int DaysCommentsAllowed
        {
            get { return daysCommentsAllowed; }
            set { daysCommentsAllowed = value; }
        }

        public bool EnableCommentDays
        {
            get { return enableCommentDays; }
            set { enableCommentDays = value; }
        }

        public bool SupressEmailAddressDisplay
        {
            get { return supressEmailAddressDisplay; }
            set { supressEmailAddressDisplay = value; }
        }


        public string EntryEditControl
        {
            get { return entryEditControl; }
            set { entryEditControl = value; }
        }

        public bool LogBlockedReferrals
        {
            get { return logBlockedReferrals; }
            set { logBlockedReferrals = value; }
        }

        public bool ShowCommentsWhenViewingEntry
        {
            get { return showCommentsWhenViewingEntry; }
            set { showCommentsWhenViewingEntry = value; }
        }

        private bool useFeedSchemeForSyndicationLinks;

        public bool UseFeedSchemeForSyndication
        {
            get { return useFeedSchemeForSyndicationLinks; }
            set { useFeedSchemeForSyndicationLinks = value; }
        }

        private int _contentLookaheadDays = 0;

        public int ContentLookaheadDays
        {
            get { return _contentLookaheadDays; }
            set { _contentLookaheadDays = value; }
        }

        public bool EnableAutoSave
        {
            get { return enableAutoSave; }
            set { enableAutoSave = value; }
        }

        private int _smtpPort = 25;

        public int SmtpPort
        {
            get { return _smtpPort; }
            set { _smtpPort = value; }
        }

        public bool CommentsAllowGravatar
        {
            get { return commentsAllowGravatar; }
            set { commentsAllowGravatar = value; }
        }

        public string CommentsGravatarNoImgPath
        {
            get { return commentsGravatarNoImgPath; }
            set { commentsGravatarNoImgPath = value; }
        }

        public string CommentsGravatarSize
        {
            get { return commentsGravatarSize; }
            set { commentsGravatarSize = value; }
        }

        public string CommentsGravatarBorder
        {
            get { return commentsGravatarBorder; }
            set { commentsGravatarBorder = value; }
        }

        public string CommentsGravatarRating
        {
            get { return commentsGravatarRating; }
            set { commentsGravatarRating = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether comments require approval.
        /// </summary>
        /// <value>
        /// <see langword="true"/> if approval is required; otherwise, <see langword="false"/>.
        /// </value>
        public bool CommentsRequireApproval
        {
            get { return commentsRequireApproval; }
            set { commentsRequireApproval = value; }
        }


        /// <summary>
        /// Gets or sets a value indicating whether HTML is allowed in comments.
        /// </summary>
        /// <value>
        /// <see langword="true"/> if HTML is allowed in comments; otherwise, <see langword="false"/>.
        /// </value>
        public bool CommentsAllowHtml
        {
            get { return commentsAllowHtml; }
            set { commentsAllowHtml = value; }
        }

        /// <summary>
        /// Gets the a collection of tags allowed in the comments.
        /// </summary>
        /// <value>The tags allowed in the comments.</value>
        /// <remarks>
        ///	The array is sorted when set during de-serialization.
        ///	</remarks>
        [XmlArray("validCommentTags", IsNullable=true)]
        [XmlArrayItem("tag")]
        public ValidTagCollection XmlAllowedTagsArray
        {
            get { return allowedTags; }
            set { allowedTags = value; }
        }

        [XmlIgnore]
        public ValidTagCollection AllowedTags
        {
            get
            {
                // if someone deleted all allowed tags, or the tags were never there he get's the default
                if (allowedTags == null || allowedTags.Count == 0)
                {
                    allowedTags = new ValidTagCollection(defaultAllowedTags);
                }

                return allowedTags;
            }
        }

        /// <summary>
        /// Gets or sets the tags allowed in the 
        /// comments as a comma separated list..
        /// </summary>
        /// <value>The tags allowed in the comments.</value>
        [XmlElement("AllowedTags")]
        [Obsolete("Please use the AllowedTags property.")]
        public string XmlAllowedTags
        {
            get { return defaultAllowedTags; }
        }

        public bool EnableCoComment
        {
            get { return enableCoComment; }
            set { enableCoComment = value; }
        }

        private bool enableSpamBlockingService;

        public bool EnableSpamBlockingService
        {
            get { return enableSpamBlockingService; }
            set { enableSpamBlockingService = value; }
        }

        private string spamBlockingServiceApiKey;

        public string SpamBlockingServiceApiKey
        {
            get { return spamBlockingServiceApiKey; }
            set { spamBlockingServiceApiKey = value; }
        }

        [XmlIgnore]
        public ISpamBlockingService SpamBlockingService
        {
            get
            {
                //TODO: this may eventually be configurable, if Akismet alternatives show up
                if (!enableSpamBlockingService || spamBlockingServiceApiKey.Length == 0)
                {
                    return null;
                }

                return new AkismetSpamBlockingService(spamBlockingServiceApiKey, root);
            }
        }

        private bool enableSpamModeration = true;

        public bool EnableSpamModeration
        {
            get { return enableSpamModeration; }
            set { enableSpamModeration = value; }
        }

        private int _entriesPerPage = 5;

        public int EntriesPerPage
        {
            get { return _entriesPerPage; }
            set { _entriesPerPage = value; }
        }

        private bool enableDailyEmailReport = false;

        public bool EnableDailyReportEmail
        {
            get { return enableDailyEmailReport; }
            set { enableDailyEmailReport = value; }
        }

        private bool useSSLForSMTP = false;

        public bool UseSSLForSMTP
        {
            get { return useSSLForSMTP; }
            set { useSSLForSMTP = value; }
        }

        public string PreferredBloggingAPI
        {
            get { return preferredBloggingAPI; }
            set { preferredBloggingAPI = value; }
        }

        private bool enableGoogleMaps = false;

        public bool EnableGoogleMaps
        {
            get { return enableGoogleMaps; }
            set { enableGoogleMaps = value; }
        }

        private string googleMapsApiKey = string.Empty;

        public string GoogleMapsApiKey
        {
            get { return googleMapsApiKey; }
            set { googleMapsApiKey = value; }
        }

        private bool enableGeoRss = false;

        public bool EnableGeoRss
        {
            get { return enableGeoRss; }
            set { enableGeoRss = value; }
        }

        private double defaultLatitude = 0;

        public double DefaultLatitude
        {
            get { return defaultLatitude; }
            set { defaultLatitude = value; }
        }

        private double defaultLongitude = 0;

        public double DefaultLongitude
        {
            get { return defaultLongitude; }
            set { defaultLongitude = value; }
        }

        private bool enableDefaultLatLongForNonGeoCodedPosts = false;

        public bool EnableDefaultLatLongForNonGeoCodedPosts
        {
            get { return enableDefaultLatLongForNonGeoCodedPosts; }
            set { enableDefaultLatLongForNonGeoCodedPosts = value; }
        }

        /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
        /* Add new properties just above this comment*/
        /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/

        [XmlAnyElement] public XmlElement[] anyElements;
        [XmlAnyAttribute] public XmlAttribute[] anyAttributes;
    }

    [Serializable]
    [XmlType(Namespace="urn:newtelligence-com:dasblog:config")]
    [XmlRoot(Namespace="urn:newtelligence-com:dasblog:config")]
    public class ContentFilter
    {
        private string expression = "";
        private string mapTo;
        private bool isRegex = false;

        public ContentFilter()
        {
        }

        public ContentFilter(string expression, string mapTo)
        {
            this.expression = expression;
            this.mapTo = mapTo;
        }

        [XmlAttribute("find")]
        public string Expression
        {
            get { return expression; }
            set { expression = value; }
        }

        [XmlAttribute("replace")]
        public string MapTo
        {
            get { return mapTo; }
            set { mapTo = value; }
        }

        [XmlAttribute("isregex")]
        public bool IsRegEx
        {
            get { return isRegex; }
            set { isRegex = value; }
        }

        [XmlAnyElement] public XmlElement[] anyElements;
        [XmlAnyAttribute] public XmlAttribute[] anyAttributes;
    }

    /// <summary>
    /// A collection of elements of type ContentFilter
    /// </summary>
    [Serializable]
    [XmlType(Namespace="urn:newtelligence-com:dasblog:config")]
    [XmlRoot(Namespace="urn:newtelligence-com:dasblog:config")]
    public class ContentFilterCollection : CollectionBase
    {
        /// <summary>
        /// Initializes a new empty instance of the ContentFilterCollection class.
        /// </summary>
        public ContentFilterCollection()
        {
        }

        /// <summary>
        /// Initializes a new instance of the ContentFilterCollection class, containing elements
        /// copied from an array.
        /// </summary>
        /// <param name="items">
        /// The array whose elements are to be added to the new ContentFilterCollection.
        /// </param>
        public ContentFilterCollection(ContentFilter[] items)
        {
            AddRange(items);
        }

        /// <summary>
        /// Initializes a new instance of the ContentFilterCollection class, containing elements
        /// copied from another instance of ContentFilterCollection
        /// </summary>
        /// <param name="items">
        /// The ContentFilterCollection whose elements are to be added to the new ContentFilterCollection.
        /// </param>
        public ContentFilterCollection(ContentFilterCollection items)
        {
            AddRange(items);
        }

        /// <summary>
        /// Adds the elements of an array to the end of this ContentFilterCollection.
        /// </summary>
        /// <param name="items">
        /// The array whose elements are to be added to the end of this ContentFilterCollection.
        /// </param>
        public virtual void AddRange(ContentFilter[] items)
        {
            foreach (ContentFilter item in items)
            {
                List.Add(item);
            }
        }

        /// <summary>
        /// Adds the elements of another ContentFilterCollection to the end of this ContentFilterCollection.
        /// </summary>
        /// <param name="items">
        /// The ContentFilterCollection whose elements are to be added to the end of this ContentFilterCollection.
        /// </param>
        public virtual void AddRange(ContentFilterCollection items)
        {
            foreach (ContentFilter item in items)
            {
                List.Add(item);
            }
        }

        /// <summary>
        /// Adds an instance of type ContentFilter to the end of this ContentFilterCollection.
        /// </summary>
        /// <param name="value">
        /// The ContentFilter to be added to the end of this ContentFilterCollection.
        /// </param>
        public virtual void Add(ContentFilter value)
        {
            List.Add(value);
        }

        /// <summary>
        /// Determines whether a specfic ContentFilter value is in this ContentFilterCollection.
        /// </summary>
        /// <param name="value">
        /// The ContentFilter value to locate in this ContentFilterCollection.
        /// </param>
        /// <returns>
        /// true if value is found in this ContentFilterCollection;
        /// false otherwise.
        /// </returns>
        public virtual bool Contains(ContentFilter value)
        {
            return List.Contains(value);
        }

        /// <summary>
        /// Return the zero-based index of the first occurrence of a specific value
        /// in this ContentFilterCollection
        /// </summary>
        /// <param name="value">
        /// The ContentFilter value to locate in the ContentFilterCollection.
        /// </param>
        /// <returns>
        /// The zero-based index of the first occurrence of the _ELEMENT value if found;
        /// -1 otherwise.
        /// </returns>
        public virtual int IndexOf(ContentFilter value)
        {
            return List.IndexOf(value);
        }

        /// <summary>
        /// Inserts an element into the ContentFilterCollection at the specified index
        /// </summary>
        /// <param name="index">
        /// The index at which the ContentFilter is to be inserted.
        /// </param>
        /// <param name="value">
        /// The ContentFilter to insert.
        /// </param>
        public virtual void Insert(int index, ContentFilter value)
        {
            List.Insert(index, value);
        }

        /// <summary>
        /// Gets or sets the ContentFilter at the given index in this ContentFilterCollection.
        /// </summary>
        public virtual ContentFilter this[int index]
        {
            get { return (ContentFilter) List[index]; }
            set { List[index] = value; }
        }

        /// <summary>
        /// Removes the first occurrence of a specific ContentFilter from this ContentFilterCollection.
        /// </summary>
        /// <param name="value">
        /// The ContentFilter value to remove from this ContentFilterCollection.
        /// </param>
        public virtual void Remove(ContentFilter value)
        {
            List.Remove(value);
        }

        /// <summary>
        /// Type-specific enumeration class, used by ContentFilterCollection.GetEnumerator.
        /// </summary>
        public class Enumerator : IEnumerator
        {
            private readonly IEnumerator wrapped;

            public Enumerator(CollectionBase collection)
            {
                wrapped = collection.GetEnumerator();
            }

            public ContentFilter Current
            {
                get { return (ContentFilter) (wrapped.Current); }
            }

            object IEnumerator.Current
            {
                get { return wrapped.Current; }
            }

            public bool MoveNext()
            {
                return wrapped.MoveNext();
            }

            public void Reset()
            {
                wrapped.Reset();
            }
        }

        /// <summary>
        /// Returns an enumerator that can iterate through the elements of this ContentFilterCollection.
        /// </summary>
        /// <returns>
        /// An object that implements System.Collections.IEnumerator.
        /// </returns>        
        public new virtual Enumerator GetEnumerator()
        {
            return new Enumerator(this);
        }
    }

    [XmlType(Namespace="urn:newtelligence-com:dasblog:config")]
    [XmlRoot(Namespace="urn:newtelligence-com:dasblog:config")]
    public class ServiceDisabledException : Exception
    {
        public ServiceDisabledException() : base("Service disabled")
        {
        }
    }
}